
using Patterns4Net.ArchitectureExplorer.Infrastructure;
using Patterns4Net.ArchitectureExplorer.ViewModels;
using Patterns4Net.ArchitectureExplorer.ViewModels.Messages;

namespace Patterns4Net.Tests.ArchitectureExplorer.ViewModels.Graph
{
    using System.Linq;
    using NUnit.Framework;
    using Patterns4Net.ArchitectureExplorer;
    using Patterns4Net.ArchitectureExplorer.Diagram;
    using Patterns4Net.ArchitectureExplorer.ViewModels.Graph;

    public class GraphViewModelFactoryTestBase : ViewModelTestBase
    {
        private Settings settings;

        protected GraphViewModelFactory GraphsFactory { get; private set; }

        protected virtual void SetUp()
        {
            base.SetUpMocks();
            this.settings = new Settings();
            this.GraphsFactory = new GraphViewModelFactory(this.EventAggregator, this.settings);
        }

        protected DiagramViewModel CreateDiagramViewModel(Diagram diagram)
        {
            var result = new DiagramViewModel(this.settings, this.GraphsFactory, this.EventAggregator);
            this.EventAggregator.Publish(new DiagramUpdatedMessage(diagram));
            return result;
        }

        protected class GraphViewModelAssert
        {
            private readonly GraphViewModel graph;

            public GraphViewModelAssert(GraphViewModel graph)
            {
                this.graph = graph;
            }

            public GraphViewModelAssert HasVertex(string name)
            {
                SafeAssert.That(
                    () => this.graph.Vertices.Any(x => x.DiagramElement.Name == name),
                    string.Format("Graph does not contain vertex {0}", name));
                return this;                
            }

            public SubGraphViewModelAssert HasSubGraph(string name)
            {
                Assert.IsTrue(
                    this.graph.SubGraphs.Any(x => x.Label == name),
                    string.Format("Graph does not contain subGraph {0}.", name));
                return new SubGraphViewModelAssert(this.graph.SubGraphs.First(x => x.Label == name));
            }

            public GraphViewModelAssert HasRelation<TRelation>(string source, string target, bool? bidirectional = null)
            {
                SafeAssert.That(
                    () => this.graph.Edges.Any(e =>
                                ((VertexViewModel)e.Source).DiagramElement.Name == source &&
                                ((VertexViewModel)e.Destination).DiagramElement.Name == target &&
                                (bidirectional == null || (e.SourceArrow != null == bidirectional.Value)) &&
                                ((dynamic)e).Relation.GetType() == typeof(TRelation)),
                    string.Format(
                        "Graph does not contain relation from {0} to {1} of type {2}", 
                        source, 
                        target, 
                        typeof(TRelation).Name));
                return this;
            }
        }

        protected class SubGraphViewModelAssert
        {
            private readonly SubGraphViewModel subGraph;

            public SubGraphViewModelAssert(SubGraphViewModel subGraph)
            {
                this.subGraph = subGraph;
            }

            public SubGraphViewModelAssert HasVertex(string name)
            {
                SafeAssert.That(
                    () => subGraph.Vertices.Any(x => x.DiagramElement.Name == name),
                    string.Format("SubGraph {0} does not contain vertex {1}", this.subGraph.Label, name));
                return this;
            }
        }
    }
}
